import * as THREE from '../../build/three.module.js';
import { GUI } from '../../jsm/libs/dat.gui.module.js';
import { OrbitControls } from '../../jsm/controls/OrbitControls.js'

// 场景
const scene = new THREE.Scene();
const sceneCube = new THREE.Scene();

// 相机
const camera = new THREE.PerspectiveCamera(70, innerWidth / innerHeight, 1, 100000);
camera.position.set(0, 0, 1000);
const cameraCube = new THREE.PerspectiveCamera(70, innerWidth / innerHeight, 1, 100000);

// 光照
const ambient = new THREE.AmbientLight(0xffffff);
scene.add(ambient);

// 贴图
const path = '../../textures/cube/Bridge2/';
const ext = '.jpg';
const urls = [
  path + 'posx' + ext, path + 'negx' + ext,
  path + 'posy' + ext, path + 'negy' + ext,
  path + 'posz' + ext, path + 'negz' + ext
]

const textureCube = new THREE.CubeTextureLoader().load(urls);
textureCube.format = THREE.RGBFormat;
textureCube.mapping = THREE.CubeReflectionMapping;
textureCube.encoding = THREE.sRGBEncoding;

const textureLoader = new THREE.TextureLoader();

const textureEquirec = textureLoader.load('../../textures/2294472375_24a3b8ef46_o.jpg');
textureEquirec.mapping = THREE.EquirectangularReflectionMapping;
textureEquirec.magFilter = THREE.LinearFilter;
textureEquirec.minFilter = THREE.LinearMipMapLinearFilter;
textureEquirec.encoding = THREE.sRGBEncoding;

const textureSphere = textureLoader.load('../../textures/metal.jpg');
textureSphere.mapping = THREE.SphericalReflectionMapping;
textureSphere.encoding = THREE.sRGBEncoding;

// 材质
const equirectShader = THREE.ShaderLib['equirect'];
const eqMtl = new THREE.ShaderMaterial({
  fragmentShader: equirectShader.fragmentShader,
  vertexShader: equirectShader.vertexShader,
  uniforms: equirectShader.uniforms,
  depthWrite: false,
  side: THREE.BackSide
})
eqMtl.uniforms['tEquirect'].value = textureEquirec;
Object.defineProperty(eqMtl, 'map', {
  get: function() {
    return this.uniforms.tEquirect.value
  }
})

const cubeShader = THREE.ShaderLib['cube'];
const cubeMtl = new THREE.ShaderMaterial({
  fragmentShader: cubeShader.fragmentShader,
  vertexShader: cubeShader.vertexShader,
  uniforms: cubeShader.uniforms,
  depthWrite: false,
  side: THREE.BackSide
});

cubeMtl.uniforms['tCube'].value = textureCube;
Object.defineProperty(cubeMtl, 'map', {
  get: function () {
    return this.uniforms.tCube.value;
  }
})

// 天空盒子
const cubeMesh = new THREE.Mesh( new THREE.BoxBufferGeometry(100, 100, 100), cubeMtl );
sceneCube.add(cubeMesh);

const geo = new THREE.SphereBufferGeometry(400, 48, 24);
const sphMtl = new THREE.MeshLambertMaterial({ envMap: textureCube });
const sphMesh = new THREE.Mesh(geo, sphMtl);
scene.add(sphMesh);

// 渲染器
const renderer = new THREE.WebGLRenderer();
renderer.autoClear = false;
renderer.setPixelRatio(devicePixelRatio);
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
renderer.gammaOutput = true;

// 控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.minDistance = 500;
controls.maxDistance = 2500;

// 事件处理
const handleResize = () => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  
  cameraCube.aspect = innerWidth / innerHeight;
  cameraCube.updateProjectionMatrix();
}
window.addEventListener('resize', handleResize);

// 渲染函数
const render = () => {
  camera.lookAt(scene.position);
  cameraCube.rotation.copy(camera.rotation);

  renderer.render(sceneCube, cameraCube);
  renderer.render(scene, camera);
}

// 动画驱动
const animate = () => {
  requestAnimationFrame(animate);

  render();
}
animate();

// gui
const params = {
  Cube: () => {
    cubeMesh.material = cubeMtl;
    cubeMesh.visible = true;
    sphMtl.envMap = textureCube;
    sphMtl.needsUpdate = true;
  },
  Equirectangular: () => {
    cubeMesh.material = eqMtl;
    cubeMesh.visible = true;
    sphMtl.envMap = textureEquirec;
    sphMtl.needsUpdate = true;
  },
  Spherical: () => {
    cubeMesh.visible = false;
    sphMtl.envMap = textureSphere;
    sphMtl.needsUpdate = true;
  },
  Refraction: false
}

const gui = new GUI();
gui.add(params, 'Cube');
gui.add(params, 'Equirectangular');
gui.add(params, 'Spherical');
gui.add(params, 'Refraction').onChange(val => {
  if (val) {
    textureEquirec.mapping = THREE.EquirectangularRefractionMapping;
    textureCube.mapping = THREE.CubeRefractionMapping;
  } else {
    textureEquirec.mapping = THREE.EquirectangularReflectionMapping;
    textureCube.mapping = THREE.CubeReflectionMapping;
  }

  sphMtl.needsUpdate = true;
})
gui.open();
